package info.batcloud.fanli.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.aliyun.opensearch.DocumentClient;
import com.aliyun.opensearch.sdk.generated.commons.OpenSearchClientException;
import com.aliyun.opensearch.sdk.generated.commons.OpenSearchException;
import com.ctospace.archit.common.pagination.Paging;
import com.jd.open.api.sdk.JdException;
import com.taobao.api.ApiException;
import com.taobao.api.TaobaoClient;
import com.taobao.api.request.TbkItemInfoGetRequest;
import com.taobao.api.request.TbkTpwdCreateRequest;
import com.taobao.api.response.TbkItemInfoGetResponse;
import com.taobao.api.response.TbkTpwdCreateResponse;
import info.batcloud.fanli.core.aliyun.OpenSearchConfig;
import info.batcloud.fanli.core.aliyun.opensearch.Cmd;
import info.batcloud.fanli.core.aliyun.opensearch.DocumentPushEntity;
import info.batcloud.fanli.core.constants.*;
import info.batcloud.fanli.core.context.StaticContext;
import info.batcloud.fanli.core.domain.CommissionItemBuyParams;
import info.batcloud.fanli.core.domain.DdkTraceInfo;
import info.batcloud.fanli.core.domain.TbkItemBuyParams;
import info.batcloud.fanli.core.dto.*;
import info.batcloud.fanli.core.entity.CommissionItem;
import info.batcloud.fanli.core.entity.Shopcat;
import info.batcloud.fanli.core.entity.TaobaoItemCat;
import info.batcloud.fanli.core.enums.CommissionItemSort;
import info.batcloud.fanli.core.enums.CommissionItemStatus;
import info.batcloud.fanli.core.enums.EcomPlat;
import info.batcloud.fanli.core.helper.PagingHelper;
import info.batcloud.fanli.core.helper.StringHelper;
import info.batcloud.fanli.core.helper.UrlHelper;
import info.batcloud.fanli.core.item.collection.JdQueryCouponGoodsSelectionCollector;
import info.batcloud.fanli.core.jos.JosApp;
import info.batcloud.fanli.core.repository.CommissionItemRepository;
import info.batcloud.fanli.core.service.*;
import info.batcloud.fanli.core.settings.*;
import info.batcloud.laxiaoke.open.domain.jd.union.ServicePromotionGoodsInfo;
import info.batcloud.laxiaoke.open.domain.jd.union.ServicePromotionGoodsInfoResult;
import info.batcloud.laxiaoke.open.request.jd.union.GoodsInfoRequest;
import info.batcloud.laxiaoke.open.response.jd.union.GoodsInfoResponse;
import info.batcloud.pdd.sdk.PddClient;
import info.batcloud.pdd.sdk.domain.ddk.Goods;
import info.batcloud.pdd.sdk.request.ddk.GoodsDetailRequest;
import info.batcloud.pdd.sdk.request.ddk.OauthGoodsPromUrlGenerateRequest;
import info.batcloud.pdd.sdk.response.ddk.GoodsDetailResponse;
import info.batcloud.pdd.sdk.response.ddk.OauthGoodsPromUrlGenerateResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@CacheConfig(cacheNames = CacheNameConstants.COMMISSION_ITEM)
public class CommissionItemServiceImpl implements CommissionItemService {

    private static final Logger logger = LoggerFactory.getLogger(CommissionItemServiceImpl.class);

    @Inject
    private CommissionItemRepository commissionItemRepository;

    @Inject
    private DocumentClient documentClient;

    @Inject
    private OpenSearchConfig openSearchConfig;

    @Inject
    private JdUnionService jdUnionService;

    @Inject
    private ChannelCommissionItemService channelCommissionItemService;

    @Inject
    private ShopcatService shopcatService;

    @Inject
    private TaobaoItemCatServiceImpl taobaoItemCatService;

    @Inject
    private SystemSettingService systemSettingService;

    @Inject
    private TaobaoUnionService taobaoUnionService;

    @Inject
    private UserService userService;

    @Inject
    private UserCommissionItemShareService userCommissionItemShareService;

    @Inject
    private MobilePushService mobilePushService;

    @Inject
    private JdUnionApiService jdUnionApiService;

    private ThreadPoolExecutor threadPoolExecutor;

    private ThreadPoolExecutor itemCacheThreadPoolExecutor;

    @Inject
    private CommissionItemService commissionItemService;

    @Inject
    private JdQueryCouponGoodsSelectionCollector jdQueryCouponGoodsCollector;

    @Inject
    private PddClient pddClient;

    @Inject
    @Qualifier(JosConstatns.UNION_APP)
    private JosApp unionApp;

    @Inject
    private TransactionTemplate transactionTemplate;

    @PostConstruct
    public void init() {
        threadPoolExecutor = new ThreadPoolExecutor(3, 100, 5, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
        itemCacheThreadPoolExecutor = new ThreadPoolExecutor(3, 100, 5, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
    }

    @Inject
    @Qualifier(TaobaoClientConstants.TAOBAO_CLIENT_ITEM_TBK)
    private TaobaoClient taobaoClient;

    @Override
    public CommissionItemDTO saveCommissionItem(CommissionItemFetchDTO item) {
        CommissionItem commissionItem = commissionItemRepository.findBySourceItemIdAndEcomPlat(item.getSourceItemId(), item.getEcomPlat());
        if (commissionItem == null) {
            commissionItem = new CommissionItem();
        }
        BeanUtils.copyProperties(item, commissionItem);
        commissionItemRepository.save(commissionItem);
        this.pushDocument(Arrays.asList(commissionItem), Cmd.ADD);
        return toCommissionItemDto(commissionItem);
    }

    @Override
    public List<CommissionItemDTO> saveCommissionItemList(List<CommissionItemFetchDTO> itemList) {
        if (itemList.size() == 0) {
            return Collections.emptyList();
        }
        List<CommissionItem> commissionItems = new ArrayList<>();

        transactionTemplate.execute((status) -> {
            Map<EcomPlat, List<Long>> couponItemIdMapByItemFrom = new HashMap<>();
            Map<String, CommissionItemFetchDTO> dtoMapBySource = new HashMap<>();
            itemList.forEach(item -> {
                dtoMapBySource.put(getEcomPlatMapKey(item.getEcomPlat(), item.getSourceItemId()), item);
                List<Long> ids = couponItemIdMapByItemFrom.get(item.getEcomPlat());
                if (ids == null) {
                    ids = new ArrayList<>();
                    couponItemIdMapByItemFrom.put(item.getEcomPlat(), ids);
                }
                ids.add(item.getSourceItemId());
            });
            //完善详细信息
            this.completeDetailInfo(dtoMapBySource, couponItemIdMapByItemFrom);
            List<CommissionItem> eciList = new ArrayList<>();
            couponItemIdMapByItemFrom.forEach((key, value) -> {
                List<CommissionItem> items = commissionItemRepository.findBySourceItemIdInAndEcomPlatIn(value, Arrays.asList(key));
                eciList.addAll(items);
            });
            Map<Long, List<CommissionItem>> channelCommissionItemMap = new HashMap<>();
            for (CommissionItem ci : eciList) {
                String key = getEcomPlatMapKey(ci.getEcomPlat(), ci.getSourceItemId());
                CommissionItemFetchDTO dto = dtoMapBySource.remove(key);
                BeanUtils.copyProperties(dto, ci);
                if (dto.getImgList() != null) {
                    ci.setImgList(dto.getImgList());
                }
                setShopcatInfo(ci, dto);
                commissionItems.add(ci);
                ci.setUpdateTime(new Date());
                if (dto.getChannelId() != null) {
                    putToChannel(channelCommissionItemMap, dto.getChannelId(), ci);
                }
            }
            List<String> saveKeys = new ArrayList<>();
            for (CommissionItemFetchDTO dto : dtoMapBySource.values()) {
                String key = dto.getSourceItemId() + " " + dto.getEcomPlat().name();
                if (saveKeys.contains(key)) {
                    continue;
                }
                saveKeys.add(key);
                CommissionItem ci = new CommissionItem();
                BeanUtils.copyProperties(dto, ci);
                ci.setImgList(dto.getImgList());
                if (dto.getImgList() != null) {
                    ci.setImgList(dto.getImgList());
                }
                this.setShopcatInfo(ci, dto);
                commissionItems.add(ci);
                if (dto.getChannelId() != null) {
                    putToChannel(channelCommissionItemMap, dto.getChannelId(), ci);
                }
                ci.setCreateTime(new Date());
                ci.setUpdateTime(ci.getCreateTime());
            }
            for (CommissionItem commissionItem : commissionItems) {
                if (commissionItem.getCouponEndTime() != null) {
                    commissionItem.setDelistTime(commissionItem.getCouponEndTime());
                }
            }
            this.commissionItemRepository.save(commissionItems);
            //处理channel
            for (Map.Entry<Long, List<CommissionItem>> entry : channelCommissionItemMap.entrySet()) {
                for (CommissionItem commissionItem : entry.getValue()) {
                    channelCommissionItemService.addCommissionItemToChannel(commissionItem.getId(), entry.getKey());
                }
            }
            return null;
        });

        threadPoolExecutor.execute(() -> pushDocument(commissionItems, Cmd.ADD));
        return commissionItems.stream().map(o -> toCommissionItemDto(o)).collect(Collectors.toList());
    }

    private void completeDetailInfo(Map<String, CommissionItemFetchDTO> dtoMapBySource, Map<EcomPlat, List<Long>> couponItemIdMapByItemFrom) {
        //完善淘客商品信息
        for (Map.Entry<EcomPlat, List<Long>> entry : couponItemIdMapByItemFrom.entrySet()) {
            if (entry.getKey() == EcomPlat.TAOBAO || entry.getKey() == EcomPlat.TMALL) {
                List<String> ids = entry.getValue().stream().map(id -> id + "").collect(Collectors.toList());
                try {
                    int page = 0;
                    int pageSize = 40;
                    while (true) {
                        int end = (page + 1) * pageSize;
                        if (end > ids.size()) {
                            end = ids.size();
                        }
                        List<String> _ids = ids.subList(page * pageSize, end);
                        TbkItemInfoGetRequest req = new TbkItemInfoGetRequest();
                        req.setNumIids(String.join(",", _ids));
                        req.setPlatform(2L);
                        TbkItemInfoGetResponse rsp = taobaoClient.execute(req);
                        if (rsp.getResults() != null) {
                            for (TbkItemInfoGetResponse.NTbkItem nTbkItem : rsp.getResults()) {
                                CommissionItemFetchDTO dto = dtoMapBySource.get(getEcomPlatMapKey(entry.getKey(), nTbkItem.getNumIid()));
                                dto.setShopTitle(nTbkItem.getNick());
                                dto.setTitle(nTbkItem.getTitle());
                                dto.setFreeShipment(nTbkItem.getFreeShipment() == null ? false : nTbkItem.getFreeShipment());
                                dto.setImgList(nTbkItem.getSmallImages());
                                dto.setItemPlace(nTbkItem.getProvcity());
                                dto.setTbkZt(nTbkItem.getMaterialLibType() != null && nTbkItem.getMaterialLibType().equals("1"));
                                TaobaoItemCat taobaoItemCat = taobaoItemCatService.findByName(nTbkItem.getCatName(), 0L);
                                if (taobaoItemCat != null) {
                                    dto.setSourceCatId(taobaoItemCat.getCid());
                                }

                            }
                            page++;
                        } else {
                            break;
                        }
                        if (end >= ids.size()) {
                            break;
                        }
                    }
                } catch (ApiException e) {

                }

            } else if (entry.getKey() == EcomPlat.JD) {
                GoodsInfoRequest request = new GoodsInfoRequest();
                request.setSkuIds(String.join(",", entry.getValue().stream().map(id -> id + "").collect(Collectors.toList())));
                try {
                    GoodsInfoResponse res = jdUnionApiService.getGoodsInfo(request);
                    ServicePromotionGoodsInfoResult result = res.getData();
                    if (result != null) {
                        for (ServicePromotionGoodsInfo info : result.getResult()) {
                            CommissionItemFetchDTO dto = dtoMapBySource.get(getEcomPlatMapKey(entry.getKey(), info.getSkuId()));
                            dto.setTitle(info.getGoodsName());
                            dto.setFreeShipment(info.getIsFreeShipping() == 1);
                            dto.setPicUrl(info.getImgUrl());
                            dto.setSourceItemUrl(info.getMaterialUrl());
                        }
                    }
                } catch (JdException e) {
                    e.printStackTrace();
                }
            } else if (entry.getKey() == EcomPlat.PDD) {
//                GoodsDetailRequest request =
            }
        }
    }

    private static String getEcomPlatMapKey(EcomPlat plat, long id) {
        return id + " " + plat.name();
    }

    private void putToChannel(Map<Long, List<CommissionItem>> channelCommissionItemMap, Long channelId, CommissionItem ci) {
        List<CommissionItem> list = channelCommissionItemMap.get(channelId);
        if (list == null) {
            list = new ArrayList<>();
            channelCommissionItemMap.put(channelId, list);
        }
        list.add(ci);
    }

    private void setShopcatInfo(CommissionItem ci, CommissionItemFetchDTO dto) {
        ShopcatDTO shopcat = null;
        if (ci.getEcomPlat() == EcomPlat.TAOBAO || ci.getEcomPlat() == EcomPlat.TMALL) {
            if (ci.getSourceCatId() != null) {
                Set<Long> shopcatIds = shopcatService.findShopcatIdByTaobaoCatId(dto.getSourceCatId());
                if (shopcatIds.size() > 0) {
                    shopcat = shopcatService.findById(shopcatIds.iterator().next());
                }
            }
        } else if (ci.getEcomPlat() == EcomPlat.JD) {
            if (dto.getSourceCatIdList() != null) {
                for (Long id : dto.getSourceCatIdList()) {
                    Set<Long> shopcatIds = shopcatService.findShopcatIdByJdCatId(id);
                    if (shopcatIds.size() > 0) {
                        shopcat = shopcatService.findById(shopcatIds.iterator().next());
                        break;
                    }
                }
            }
        }
        if (shopcat != null) {

        } else if (dto.getShopcatId() != null) {
            shopcat = shopcatService.findById(dto.getShopcatId());
        }
        if (shopcat != null) {
            shopcat = shopcatService.findReal(shopcat);
            Shopcat sc = new Shopcat();
            sc.setId(shopcat.getId());
            sc.setPath(shopcat.getPath());
            ci.setShopcat(sc);
        }
    }

    @Override
    public synchronized List<CommissionItemDTO> saveCommissionItemListSync(List<CommissionItemFetchDTO> itemList) {
        return saveCommissionItemList(itemList);
    }

    @Override
    public List<CommissionItemDTO> findByIdList(List<Long> ids) {
        Iterable<CommissionItem> commissionItems = commissionItemRepository.findAll(ids);
        List<CommissionItemDTO> list = new ArrayList<>();
        for (CommissionItem commissionItem : commissionItems) {
            list.add(toCommissionItemDto(commissionItem));
        }
        return list;
    }

    private void pushDocument(Collection<CommissionItem> itemList, Cmd cmd) {
        if (itemList.size() == 0) {
            return;
        }
        logger.info("更新文档到开放搜索");
        List<DocumentPushEntity<CommissionItemDocument>> pushList = new ArrayList<>();
        List<Long> commissionItemIds = new ArrayList<>();
        Map<Long, CommissionItemDocument> documentMap = new HashMap<>();
        for (CommissionItem commissionItem : itemList) {
            DocumentPushEntity<CommissionItemDocument> entity = new DocumentPushEntity<>();
            entity.setCmd(cmd);
            CommissionItemDocument doc = createCommissionItemDocument(commissionItem);
            entity.setFields(doc);
            pushList.add(entity);
            documentMap.put(commissionItem.getId(), doc);
            commissionItemIds.add(commissionItem.getId());
        }
        Map<Long, List<Long>> channelListMap = channelCommissionItemService.findChannelIdListByItemIdList(commissionItemIds);
        for (Map.Entry<Long, List<Long>> entry : channelListMap.entrySet()) {
            documentMap.get(entry.getKey()).setChannelIds(entry.getValue());
        }
        try {
            logger.info("开始push文档到开放搜索");
            this.documentClient.push(JSON.toJSONString(pushList), openSearchConfig.getApp(), OpenSearchConstans.TABLE_NAME_COMMISSION_ITEM);
            logger.info("更新文档到开放搜索成功");
        } catch (OpenSearchException e) {
            logger.error("更新item文档出错", e);
            throw new RuntimeException(e);
        } catch (OpenSearchClientException e) {
            logger.error("更新item文档出错", e);
            throw new RuntimeException(e);
        }
    }

    private CommissionItemDocument createCommissionItemDocument(CommissionItem commissionItem) {
        CommissionItemDocument doc = new CommissionItemDocument();
        doc.setId(commissionItem.getId());
        doc.setCommissionRate(commissionItem.getCommissionRate());
        doc.setPicUrl(commissionItem.getPicUrl());
        doc.setPrice(commissionItem.getPrice());
        doc.setSales(commissionItem.getSales());
        doc.setTitle(commissionItem.getTitle());
        doc.setShopTitle(commissionItem.getShopTitle());
        doc.setItemPlace(commissionItem.getItemPlace());
        doc.setEcomPlat(commissionItem.getEcomPlat().name());
        doc.setCouponValue(commissionItem.getCouponValue());
        doc.setListTime(commissionItem.getListTime().getTime());
        doc.setDelistTime(commissionItem.getDelistTime().getTime());
        doc.setSummary(commissionItem.getSummary());
        doc.setOriginPrice(commissionItem.getOriginPrice());
        doc.setTbkZt(commissionItem.isTbkZt() ? 1 : 0);
        doc.setRecommend(commissionItem.isRecommend() ? 1 : 0);
        doc.setFreeShipment(commissionItem.isFreeShipment() ? 1 : 0);
        doc.setJdSale(commissionItem.isJdSale() ? 1 : 0);
        doc.setDescription(commissionItem.getDescription());
        doc.setHasDescription(StringUtils.isNotEmpty(commissionItem.getDescription()) ? 1 : 0);
        if (commissionItem.getShopcat() != null) {
            doc.setShopcatIds(Arrays.stream(commissionItem.getShopcat().getPath().split("/"))
                    .map(o -> Long.valueOf(o)).collect(Collectors.toList()));
        }
        if (commissionItem.getCouponEndTime() != null) {
            doc.setCouponEndTime(commissionItem.getCouponEndTime().getTime());
        }
        if (commissionItem.getCouponStartTime() != null) {
            doc.setCouponStartTime(commissionItem.getCouponStartTime().getTime());
        }
        doc.setHighCommission(commissionItem.isHighCommission() ? 1 : 0);
        doc.setCoupon(commissionItem.isCoupon() ? 1 : 0);
        doc.setCouponRemainCount(commissionItem.getCouponRemainCount() == null ? 0 : commissionItem.getCouponRemainCount());
        doc.setCouponTotalCount(commissionItem.getCouponTotalCount() == null ? 0 : commissionItem.getCouponTotalCount());
        return doc;
    }

    @Override
    public void updateCommissionItem(long itemId, CommissionItemUpdateDTO item) {
        CommissionItem ci = commissionItemRepository.findOne(itemId);
        BeanUtils.copyProperties(item, ci);
        commissionItemRepository.save(ci);
    }

    public Page<CommissionItem> searchCommissionItem(SearchParam param) {

        Specification<CommissionItem> specification = (root, query, cb) -> {
            Predicate predicate = cb.conjunction();
            List<Expression<Boolean>> expressions = predicate.getExpressions();
            if (param.getStartPrice() != null) {
                expressions.add(cb.greaterThanOrEqualTo(root.get("price"), param.getStartPrice()));
            }
            if (param.getEndPrice() != null) {
                expressions.add(cb.lessThanOrEqualTo(root.get("price"), param.getEndPrice()));
            }
            if (StringUtils.isNotBlank(param.getKeywords())) {
                expressions.add(cb.like(root.get("title"), "%" + param.getKeywords() + "%"));
            }
            if (StringUtils.isNotBlank(param.getCatPath())) {
                expressions.add(cb.like(root.get("catPath"), param.getCatPath() + "%"));
            }
            if (param.getMaxSales() != null) {
                expressions.add(cb.lessThanOrEqualTo(root.get("sales"), param.getMaxSales()));
            }
            if (param.getMinSales() != null) {
                expressions.add(cb.greaterThanOrEqualTo(root.get("sales"), param.getMinSales()));
            }
            if (param.getStatus() != null) {
                expressions.add(cb.equal(root.get("status"), param.getStatus()));
            }
            if (param.getMaxCouponValue() != null) {
                expressions.add(cb.lessThanOrEqualTo(root.get("couponValue"), param.getMaxCouponValue()));
            }
            return predicate;
        };
        Sort sort = null;
        if (param.getSort() != null) {
            switch (param.getSort()) {
                case PRICE_ASC:
                    sort = new Sort(Sort.Direction.ASC, "price");
                    break;
                case PRICE_DESC:
                    sort = new Sort(Sort.Direction.DESC, "price");
                    break;
                case NONE:
                    break;
                case SALES_DESC:
                    sort = new Sort(Sort.Direction.DESC, "sales");
                    break;
                case LIST_TIME_DESC:
                    sort = new Sort(Sort.Direction.ASC, "listTime");
                    break;
                case ID_DESC:
                    sort = new Sort(Sort.Direction.DESC, "id");
                    break;
                case COMMISSION_VALUE_DESC:
                    sort = new Sort(Sort.Direction.ASC, "commissionRate*price");
                    break;
                case UPDATE_TIME_DESC:
                    sort = new Sort(Sort.Direction.DESC, "updateTime");
                    break;
            }
        }
        Pageable pageable = new PageRequest(param.getPage() - 1,
                param.getPageSize(), sort);
        Page<CommissionItem> page = commissionItemRepository.findAll(specification, pageable);
        return page;
    }

    @Override
    public Paging<CommissionItemDTO> search(SearchParam param) {
        Page<CommissionItem> page = searchCommissionItem(param);
        return PagingHelper.of(page, item -> toCommissionItemDto(item), param.getPage(), param.getPageSize());
    }

    @Override
    public void pushDocumentByItemIdList(List<Long> itemIds) {
        this.pushDocument(commissionItemRepository.findByIdIn(itemIds), Cmd.ADD);
    }

    @Override
    @Transactional
    public ShareInfo findShareInfo(long couponItemId, Long userId) {
        CommissionItemDTO ci = findById(couponItemId);
        return findShareInfo(ci, userId);
    }

    @Override
    @Transactional
    public ShareInfo findShareInfo(CommissionItemDTO ci, Long userId) {
        ShareInfo si = new ShareInfo();
        si.setUserId(userId);
        UserCommissionItemShareDTO shareDto = userCommissionItemShareService.findValidUserCommissionItemShare(ci.getId(), userId);
        List<String> rows = new ArrayList<>();
        rows.add(StaticContext.messageSource.getMessage(MessageKeyConstants.COMMISSION_ITEM_SHARE_TEXT,
                new Object[]{"【" + ci.getEcomPlat().getTitle() + "】" + StringUtils.defaultIfEmpty(ci.getDescription(), ci.getTitle()),
                        ci.getPrice(), ci.getOriginPrice(), shareDto.getShortUrl()}, null));
        if (shareDto.getKl() == null) {
            try {
                if (ci.getEcomPlat() == EcomPlat.TMALL || ci.getEcomPlat() == EcomPlat.TAOBAO) {
                    TbkTpwdCreateRequest request = new TbkTpwdCreateRequest();
                    request.setUrl(UrlHelper.toSSLUrl(shareDto.getClickUrl()));
                    request.setText(ci.getTitle());
                    TbkTpwdCreateResponse response;
                    response = taobaoClient.execute(request);
                    shareDto.setKl(response.getData().getModel());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (shareDto.getKl() != null) {
            rows.add(StaticContext.messageSource.getMessage(MessageKeyConstants.COMMISSION_ITEM_SHARE_TEXT_KL,
                    new Object[]{shareDto.getKl()}, null));
        }
        if (StringUtils.isBlank(shareDto.getClickUrl())) {
            si.setClickUrl(shareDto.getClickUrl());
        } else {
            si.setClickUrl(StringUtils.isBlank(ci.getCouponClickUrl()) ? ci.getSourceItemClickUrl() : ci.getCouponClickUrl());
        }
        si.setEcomPlatTitle(ci.getEcomPlatTitle());
        si.setTitle(StringUtils.defaultIfEmpty(ci.getDescription(), ci.getTitle()));
        si.setPrice(ci.getPrice());
        si.setOriginPrice(ci.getOriginPrice());
        si.setClickUrl(shareDto.getClickUrl());
        si.setUrl(shareDto.getUrl());
        si.setKl(shareDto.getKl());
        si.setShareText(String.join("\n", rows));
        si.setShortUrl(shareDto.getShortUrl());
        si.setTaobaoRelationId(shareDto.getTaobaoRelationId());
        return si;
    }

    @Override
    public void rePushDocument() {
        this.clean();
        SearchParam param = new SearchParam();
        param.setPageSize(1000);
        param.setStatus(CommissionItemStatus.ONSALE);
        param.setSort(CommissionItemSort.ID_DESC);
        ItemSelectionSetting setting = systemSettingService.findActiveSetting(ItemSelectionSetting.class);
        param.setMinSales(setting.getMinSales());
        int page = 1;
        while (true) {
            param.setPage(page++);
            Page<CommissionItem> paging = this.searchCommissionItem(param);
            this.pushDocument(paging.getContent(), Cmd.ADD);
            if (paging.getContent().size() < 1000) {
                break;
            }
        }
    }

    @Override
    public CommissionItemDTO findById(long id) {
        CommissionItem ci = commissionItemRepository.findOne(id);
        if (ci == null) {
            return null;
        }
        switch (ci.getEcomPlat()) {
            case PDD:
                //如果发现没有图片集，则进行读取。
                if (ci.getImgList() == null || ci.getImgList().size() == 0) {
                    GoodsDetailRequest request = new GoodsDetailRequest();
                    request.setGoodsIdList(Arrays.asList(ci.getSourceItemId()));
                    GoodsDetailResponse response = pddClient.execute(request);
                    List<Goods> goodsList = response.getData().getGoodsList();
                    if (goodsList.size() > 0) {
                        Goods goods = goodsList.get(0);
                        ci.setImgList(goods.getGoodsGalleryUrls());
                        ci.setDescription(goods.getGoodsDesc());
                        commissionItemRepository.save(ci);
                    }
                }
                break;
        }
        return toCommissionItemDto(ci);
    }

    @Override
    public CommissionItemDTO findOrFetchBySourceItemIdAndEcomPlat(long sourceItemId, EcomPlat ecomPlat) {
        CommissionItemFetchDTO fetchBO = commissionItemService.fetchOnlineBySourceItemIdAndEcomPlat(sourceItemId, ecomPlat);
        List<CommissionItemFetchDTO> list = new ArrayList<>();
        list.add(fetchBO);
        CommissionItemDTO item = this.commissionItemService.saveCommissionItemListSync(list).get(0);
        return item;
    }

    @Override
    public CommissionItemDTO findBySourceItemIdAndEcomPlat(long sourceItemId, EcomPlat ecomPlat) {
        CommissionItem ci = commissionItemRepository.findBySourceItemIdAndEcomPlat(sourceItemId, ecomPlat);
        if (ci == null) {
            return null;
        }
        return toCommissionItemDto(ci);
    }

    @Override
    public CommissionItemDTO findOnlineBySourceItemIdAndEcomPlat(long sourceItemId, EcomPlat ecomPlat) {
        //直接从在线接口中查询
        CommissionItemDTO commissionItemDTO = new CommissionItemDTO();
        BeanUtils.copyProperties(fetchOnlineBySourceItemIdAndEcomPlat(sourceItemId, ecomPlat), commissionItemDTO);
        commissionItemDTO.setShareCommission(this.findShareCommission(commissionItemDTO.getPrice(), commissionItemDTO.getCommissionRate()));
        return commissionItemDTO;
    }

    @Override
    public CommissionItemFetchDTO fetchOnlineBySourceItemIdAndEcomPlat(long sourceItemId, EcomPlat ecomPlat) {
        switch (ecomPlat) {
            case TAOBAO:
                return fromTaobao(sourceItemId);
            case TMALL:
                return fromTmall(sourceItemId);
            case JD:
                return fromJD(sourceItemId);
            case PDD:
                return fromPdd(sourceItemId);
        }
        return null;
    }

    private CommissionItemFetchDTO fromJD(long skuId) {
        JdQueryCouponGoodsSelectionCollector.JdQueryCouponGoodsContext context = new JdQueryCouponGoodsSelectionCollector.JdQueryCouponGoodsContext();
        context.setSkuIds(skuId + "");
        context.setPageSize(1);
        context.setMaxPage(1);
        context.setStartPage(1);
        final List<CommissionItemFetchDTO> list = new ArrayList<>();
        jdQueryCouponGoodsCollector.collect(context, fetchBOPaging -> list.addAll(fetchBOPaging.getResults()));
        return list.size() >= 1 ? list.get(0) : null;
    }

    private CommissionItemFetchDTO fromPdd(long goodsId) {
        GoodsDetailRequest request = new GoodsDetailRequest();
        request.setGoodsIdList(Arrays.asList(goodsId));
        GoodsDetailResponse response = pddClient.execute(request);
        List<Goods> goodsList = response.getData().getGoodsList();
        Goods goods = goodsList.get(0);
        CommissionItemFetchDTO dto = new CommissionItemFetchDTO();
        Date now = new Date();
        dto.setListTime(now);
        /**
         * 商品的下架时间为当前的日期+7天，优惠券的下架时间，活动的下架时间取最大者
         * */
        Date delistTime = DateUtils.addDays(now, 7);
        dto.setCoupon(goods.getCouponStartTime() > 0);
        Date couponEndTime;
        if (goods.getCouponEndTime() > 0) {
            couponEndTime = new Date(goods.getCouponEndTime());
        } else {
            couponEndTime = new Date();
        }
        dto.setDelistTime(Collections.max(Arrays.asList(delistTime, couponEndTime)));
        dto.setCouponStartTime(goods.getCouponStartTime() > 0 ? new Date(goods.getCouponStartTime()) : null);
        dto.setSourceCatIdList(goods.getCatIds());
        dto.setShopTitle(goods.getMallName());
        dto.setCouponRemainCount(100);
        dto.setCouponTotalCount(100);

        dto.setCouponValue(goods.getCouponDiscount() / 100f);
        dto.setSourceItemUrl("");
        dto.setSourceItemId(goods.getGoodsId());
        dto.setTitle(goods.getGoodsName());
        dto.setSourceItemClickUrl("");
        dto.setCouponClickUrl("");
        dto.setOriginPrice(goods.getMinGroupPrice() / 100f);
        float couponStartFee = goods.getCouponMinOrderAmount();
        dto.setCouponThresholdAmount(couponStartFee);
        dto.setCommissionRate(goods.getPromotionRate() / 10);
        dto.setEcomPlat(EcomPlat.PDD);
        dto.setSeckill(false);
        dto.setImgList(new ArrayList<>());
        dto.setPicUrl(StringUtils.defaultIfEmpty(goods.getGoodsImageUrl(), goods.getGoodsThumbnailUrl()));
        dto.setSales(goods.getSoldQuantity());
        dto.setStatus(CommissionItemStatus.ONSALE);
        dto.setImgList(goods.getGoodsGalleryUrls());
        dto.setContent(goods.getGoodsDesc());
        return dto;
    }

    private CommissionItemFetchDTO fromTmall(long numIid) {
        return commissionItemService.cacheCommissionItemByEcomPlatAndSourceItemId(EcomPlat.TMALL, numIid, null);
    }

    private CommissionItemFetchDTO fromTaobao(long numIid) {
        return commissionItemService.cacheCommissionItemByEcomPlatAndSourceItemId(EcomPlat.TAOBAO, numIid, null);
    }

    /**
     * 寻找下架时间已经过的商品进行下架操作
     */
    @Override
    public void clean() {
        Date now = new Date();
        while (true) {
            List<CommissionItem> list = commissionItemRepository.findTop1000ByDelistTimeLessThanAndStatus(now, CommissionItemStatus.ONSALE);
            if (list.size() == 0) {
                return;
            }
            for (CommissionItem commissionItem : list) {
                commissionItem.setStatus(CommissionItemStatus.INSTOCK);
            }
            this.commissionItemRepository.save(list);
            this.pushDocument(list, Cmd.DELETE);
        }
    }

    @Override
    public void clean(SearchParam param) {
        logger.info("开始商品清理");
        int page = 1;
        param.setPageSize(500);
        param.setSort(CommissionItemSort.ID_DESC);
        while (true) {
            param.setPage(page++);
            Page<CommissionItem> pageResult = searchCommissionItem(param);
            if (pageResult.getContent().size() == 0) {
                break;
            }

            for (CommissionItem commissionItem : pageResult.getContent()) {
                commissionItem.setStatus(CommissionItemStatus.INSTOCK);
            }
            this.commissionItemRepository.save(pageResult.getContent());
            this.pushDocument(pageResult.getContent(), Cmd.DELETE);
        }
        logger.info("开始商品清理完成");
    }

    @Override
    public void setStatus(CommissionItemStatus status, List<Long> ids) {
        List<CommissionItem> commissionItems = commissionItemRepository.findByIdIn(ids);
        for (CommissionItem commissionItem : commissionItems) {
            commissionItem.setStatus(status);
        }
        commissionItemRepository.save(commissionItems);
        //更新open search
        if (status == CommissionItemStatus.ONSALE) {
            this.pushDocument(commissionItems, Cmd.ADD);
        } else {
            this.pushDocument(commissionItems, Cmd.DELETE);
        }
    }

    @Override
    @Cacheable(key = "'TITLE_SEGMENT_' + #commissionItemId")
    public List<String> findTitleSegmentById(long commissionItemId) {
        CommissionItem ci = commissionItemRepository.findOne(commissionItemId);
        return StringHelper.segment(ci.getTitle());
    }

    @Override
    public CommissionItemDTO toCommissionItemDto(CommissionItem ci) {
        CommissionItemDTO dto = new CommissionItemDTO();
        BeanUtils.copyProperties(ci, dto);
        dto.setShareCommission(this.findShareCommission(dto.getPrice(), dto.getCommissionRate()));
        if (ci.getShopcat() != null) {
            dto.setShopcatTitle(ci.getShopcat().getTitle());
        }
        return dto;
    }

    @Override
    @Cacheable(key = "'COMMISSION_RATE_BY_ECOMPLAT_SOURCE_ITEM_ID_' + #ecomPlat.name() + '_' + #sourceItemId")
    public float cacheCommissionRateByEcomPlatAndSourceItemId(EcomPlat ecomPlat, long sourceItemId, float commissionRate) {
        return commissionRate;
    }

    @Override
    @Cacheable(key = "'COMMISSION_ITEM_BO_BY_ECOMPLAT_SOURCE_ITEM_ID_' + #ecomPlat.name() + '_' + #sourceItemId", unless = "#result == null")
    public CommissionItemFetchDTO cacheCommissionItemByEcomPlatAndSourceItemId(EcomPlat ecomPlat,
                                                                               long sourceItemId, CommissionItemFetchDTO commissionItemBO) {
        return commissionItemBO;
    }

    @Override
    public void cacheCommissionItemList(List<CommissionItemFetchDTO> list) {
        itemCacheThreadPoolExecutor.execute(() -> {
            for (CommissionItemFetchDTO dto : list) {
                commissionItemService.cacheCommissionItemByEcomPlatAndSourceItemId(dto.getEcomPlat(), dto.getSourceItemId(), dto);
            }
        });
    }

    @Override
    public <T> CommissionItemBuyParams<T> findBuyParams(long id, Long userId) {
        CommissionItem ci = commissionItemRepository.findOne(id);
        CommissionItemBuyParams buyParams = new CommissionItemBuyParams();
        buyParams.setEcomPlat(ci.getEcomPlat());
        if ((ci.getEcomPlat() == EcomPlat.TAOBAO || ci.getEcomPlat() == EcomPlat.TMALL)) {
            TbkItemBuyParams params = new TbkItemBuyParams();
            TaobaoUnionSetting taobaoUnionSetting = systemSettingService.findActiveSetting(TaobaoUnionSetting.class);
            params.setAdzoneId(taobaoUnionSetting.getRebateAdzoneId());
            params.setPid(taobaoUnionSetting.getRebatePid());
            params.setUnionId(taobaoUnionSetting.getUnionId());
            params.setClickUrl(StringUtils.isNotEmpty(ci.getCouponClickUrl()) ? ci.getCouponClickUrl() : ci.getSourceItemClickUrl());
            params.setClickUrl(completeUrl(StringUtils.isNotBlank(params.getClickUrl()) ? params.getClickUrl() : detectCommissionItemUrl(ci)));
            params.setSpecialId(userService.findOrGenerateTaobaoSpecialId(userId));
            buyParams.setData(params);
        } else if (ci.getEcomPlat() == EcomPlat.JD) {
            String url = jdUnionService.getCouponUrl(userId, ci.getSourceItemId(), ci.getCouponClickUrl());
            buyParams.setData(completeUrl(StringUtils.defaultIfEmpty(url, ci.getSourceItemUrl())));
        } else if (ci.getEcomPlat() == EcomPlat.PDD) {
            DdkAuthSetting ddkAuthSetting = systemSettingService.findActiveSetting(DdkAuthSetting.class);
            DdkSetting ddkSetting = systemSettingService.findActiveSetting(DdkSetting.class);
            OauthGoodsPromUrlGenerateRequest request = new OauthGoodsPromUrlGenerateRequest();
            DdkTraceInfo traceInfo = new DdkTraceInfo();
            traceInfo.setUserId(userId);
            request.setCustomParameters(traceInfo.toJson());
            request.setGenerateShortUrl(true);
            request.setGoodsIdList(Arrays.asList(ci.getSourceItemId()));
            request.setPid(ddkSetting.getPid());
            OauthGoodsPromUrlGenerateResponse response = pddClient.execute(request, ddkAuthSetting.getAccessToken());
            buyParams.setData(response.getData().getGoodsPromotionUrlList().get(0));
        }
        return buyParams;
    }

    private String detectCommissionItemUrl(CommissionItem ci) {
        if (StringUtils.isNotBlank(ci.getCouponClickUrl())) {
            return ci.getCouponClickUrl();
        }
        if (StringUtils.isNotBlank(ci.getSourceItemClickUrl())) {
            return ci.getSourceItemClickUrl();
        }
        if (StringUtils.isNotBlank(ci.getSourceItemUrl())) {
            return ci.getSourceItemUrl();
        }
        return "";
    }

    private String completeUrl(String url) {
        if (url.startsWith("//")) {
            return "http:" + url;
        }
        return url;
    }

    private String pidRegex = "[?&](pid=.+)+?[&$]?";

    private String replaceCouponUrlPic(String couponUrl, String pid) {
        Matcher m = Pattern.compile(pidRegex).matcher(couponUrl);
        if (m.find()) {
            return couponUrl.replace(m.group(1), "pid=" + pid);
        } else {
            return couponUrl.indexOf("?") != -1 ? (couponUrl + "&pid=" + pid) : (couponUrl + "?pid=" + pid);
        }
    }

    @Override
    public float findShareCommission(float price, float commissionRate) {
        CommissionAllotSetting setting = systemSettingService.findActiveSetting(CommissionAllotSetting.class);
        float commissionFee = price * commissionRate / 100;
        //减去保留的佣金比例
        commissionFee = (setting.getPlusCommissionRate() / 100 * commissionFee);
        return commissionFee;
    }

}
